import string
import tkinter as tk
import random
from tkinter import messagebox

excluded_chars = "Il0oO"
#default_special_chars = "!@#$%^&*()_+-"

root = tk.Tk()
root.geometry("280x560")
#root.resizable(width=False, height=True)
root.minsize(280,330)
root.maxsize(280,600)
root.title("Passwd")
root.resizable(0,1)

def generate_password(length, chars, password_length):
    password = ''
    char_pool = []
    include_upper = use_upper.get()
    include_lower = use_lower.get()
    include_num = use_num.get()
    include_special = use_special.get()
    
    if include_upper:
        char_pool.extend(string.ascii_uppercase)
    if include_lower:
        char_pool.extend(string.ascii_lowercase)
    if include_num:
        char_pool.extend(string.digits)
        
    special_chars = []
    if include_special:
        special_chars_entry = special_entry.get().strip()
        if special_chars_entry:
            special_chars.extend(special_chars_entry)
        else:
            special_chars.extend(default_special_chars)
            
        char_pool.extend(special_chars)
    
    char_pool = [c for c in char_pool if c not in excluded_chars]
    
    if len(char_pool) == 0:
        messagebox.showwarning("Warning", "Please select at least one valid character type.")
        return
    
    if include_upper:
        # ensure at least one uppercase character is included
        password += random.choice(string.ascii_uppercase)
        length -= 1
    
    if include_lower:
        # ensure at least one lowercase character is included
        password += random.choice(string.ascii_lowercase)
        length -= 1
    
    if include_num:
        # ensure at least one numeric character is included
        password += random.choice(string.digits)
        length -= 1
    
    if include_special:
        # ensure at least one special character is included
        if len(special_chars) == 0:
            special_chars = char_pool
        password += random.choice(special_chars)
        length -= 1
    
    if len(char_pool) == 0:
        messagebox.showwarning("Warning", "Please select at least one valid character type.")
        return
    
    password += ''.join(random.choices(char_pool, k=length))
    
    # Replace excluded characters with allowed ones
    password = [c if c not in excluded_chars else random.choice(char_pool) for c in password]
    password = ''.join(password)
    
    password_list = list(password)
    random.shuffle(password_list)
    password = ''.join(password_list)
    
    # Check if all selected characters are included in the password
    if include_upper and not any(c in password for c in string.ascii_uppercase):
        password += random.choice(string.ascii_uppercase)
    if include_lower and not any(c in password for c in string.ascii_lowercase):
        password += random.choice(string.ascii_lowercase)
    if include_num and not any(c in password for c in string.digits):
        password += random.choice(string.digits)
    if include_special and not any(c in password for c in special_chars):
        password += random.choice(special_chars)
    
    if len(password) != password_length:
        return generate_password(length, chars, password_length)
    
    return password


def generate_and_display_password():
        password = None
        password_end = ""
        password_count = length_count.get()
        for _ in range(password_count):
            if not any((use_upper.get(), use_lower.get(), use_num.get(), use_special.get())):
                messagebox.showwarning("Warning", "Please select at least one checkbox.")
                return
            include_special = use_special.get()
            special_chars = special_entry.get().strip()
            if include_special and not special_chars:
                messagebox.showwarning("Warning", "Please enter some special characters.")
                return
            custom_chars = "".join(c for c in (
                string.ascii_uppercase if use_upper.get() else "",
                string.ascii_lowercase if use_lower.get() else "",
                string.digits if use_num.get() else "",
                special_chars if include_special else "",
            ) if c not in excluded_chars)
            password_length = length_scale.get()
            password = None
            while not password:
                password = generate_password(password_length, custom_chars, password_length)
                password_end += password + "\n"
            result_label.config(text=password_end, font=("Arial", 17, "bold"))

def copy_to_clipboard_1():
    a = length_scale.get()
    password = result_label.cget("text")
    password = password[0:a]
    root.clipboard_clear()
    root.clipboard_append(password)

def copy_to_clipboard_a():
    password = result_label.cget("text")
    password = password[0:-1]
    root.clipboard_clear()
    root.clipboard_append(password)

length_scale = tk.Scale(root, from_=8, to=15, orient=tk.HORIZONTAL, label="Length")
length_scale.set(8)
length_scale.pack()

length_count = tk.Scale(root, from_=1, to=10, orient=tk.HORIZONTAL, label="Count")
length_count.set(1)
length_count.pack()

check_button_frame = tk.Frame(root)
check_button_frame.pack()
#custom_special_entry = tk.Entry(root)
#custom_special_entry.pack()

use_upper = tk.BooleanVar()
use_upper.set(True)
upper_checkbutton = tk.Checkbutton(check_button_frame, text="Upper", variable=use_upper)
upper_checkbutton.grid(row=0, column=0, padx=0, pady=0)

use_lower = tk.BooleanVar()
use_lower.set(True)
lower_checkbutton = tk.Checkbutton(check_button_frame, text="Lower", variable=use_lower)
lower_checkbutton.grid(row=0, column=1, padx=0, pady=0)

use_num = tk.BooleanVar()
use_num.set(True)
num_checkbutton = tk.Checkbutton(check_button_frame, text="Num", variable=use_num)
num_checkbutton.grid(row=1, column=0, padx=0, pady=0)

use_special = tk.BooleanVar()
use_special.set(True)
special_checkbutton = tk.Checkbutton(check_button_frame, text="Special", variable=use_special)
special_checkbutton.grid(row=1, column=1, padx=0, pady=0)

default_special_chars = "!@#$%^&*()_+-"
special_entry = tk.Entry(check_button_frame)
special_entry.insert(0, default_special_chars)
special_entry.grid(row=2, columnspan=2, padx=0, pady=0)

button = tk.Button(root, text="Generate Password", command=generate_and_display_password)
button.pack(pady=0)

copy_button = tk.Button(root, text="Copy 1", command=copy_to_clipboard_1)
copy_button.pack(pady=0)

copy_button = tk.Button(root, text="Copy All", command=copy_to_clipboard_a)
copy_button.pack(pady=0)

result_label = tk.Label(root, text="", font=("Arial", 17, "bold"))
result_label.pack()

root.mainloop()
